#include "stdafx.h"

#include "..\TddDialog.h"
using namespace TddGui;

#include "FindWindows.h"

namespace Slow
{
TESTCLASS(TddDialogTests)
{
	class DialogThread
	{
		CTddGuiDialog m_md;
		HWND m_dlg;

	public:
		DialogThread() : m_dlg(NULL) {}
		~DialogThread()
		{
			if (m_dlg != NULL)
				::EndDialog(m_dlg, 0);

			/* N.B.:  EndDialog does not block when destroying the HWND (per MSDN).  So there's a race-condition here.  
			   It's minor, only shows up in DEBUG, but the CWindowImplRoot dtor ASSERTs that its hwnd is not NULL yet, 
			   about 1 time in 10.  So I'll poll just a bit.
			*/
			while (m_md.m_hWnd != NULL)
			{
				::Sleep(1);
			}
		}
		
		HWND StartDialog(HWND notThisWindow)
		{
			HANDLE h = ::CreateThread(NULL, 0, ThreadProc, this, 0, NULL);
			if (h != NULL)
				::CloseHandle(h);

			return m_dlg = WaitForDialog(notThisWindow);
		}
		static HWND FindDialog(HWND notThisWindow=NULL)
		{
			// wait a sec for window to come up
			TitlePredicate tp(L"Tdd-Gui");
			VisiblePredicate vp;
			ProcessPredicate pp(::GetCurrentProcessId());
			DialogPredicate dp;

			class NotThisHWNDPredicate
			{
				HWND m_hwnd;
			public:
				NotThisHWNDPredicate(HWND hwnd) : m_hwnd(hwnd) {}
				bool operator()(HWND hwnd) const
				{
					return hwnd != m_hwnd;
				}
			} notThisOne(notThisWindow);

			return ::FindDesiredWindow(vp, dp, pp, tp, notThisOne);
		}

	private:
		static HWND WaitForDialog(HWND notThisWindow=NULL)
		{
			for(int i=0; i<100; ++i)
			{
				HWND hwnd = FindDialog(notThisWindow);
				if (hwnd != NULL)
					return hwnd;
				::Sleep(10);
			}
			return NULL;
		}

		static DWORD WINAPI ThreadProc(LPVOID lp)
		{
			return (reinterpret_cast<DialogThread*>(lp))->ThreadProc();
		}
		DWORD ThreadProc()
		{
			m_md.DoModal();
			return 0;
		}
	};

	DialogThread* dt;
	void TestInitialize() { dt = new DialogThread(); }
	void TestCleanup() { delete dt; }

	TESTMETHOD(InitDisablesRunButton)
	{
		HWND orig = DialogThread::FindDialog(); // either NULL for console runner, or non-NULL for gui runner
		HWND dlg = dt->StartDialog(orig);

		TddAssert().IsTrue(dlg != NULL, L"main dialog should exist");
		TddAssert().IsFalse(::IsWindowEnabled(::GetDlgItem(dlg, IDC_BUTTON_RUN)));
	}

	TESTMETHOD(InitCentersDialog)
	{
		HWND dlg = dt->StartDialog(DialogThread::FindDialog());

		// verify that window is centered
		RECT rectDialog = {0};
		::GetWindowRect(dlg, &rectDialog);
		
		HMONITOR hMonitor = ::MonitorFromWindow(dlg, MONITOR_DEFAULTTONEAREST);
		MONITORINFO minfo = { sizeof(MONITORINFO), 0 };
		::GetMonitorInfo(hMonitor, &minfo);
		RECT rectParent = minfo.rcWork;

		TddAssert().AreEqual((rectDialog.left + rectDialog.right)/2, (rectParent.left + rectParent.right)/2, L"centers (x) should be equal");
		TddAssert().AreEqual((rectDialog.top + rectDialog.bottom)/2, (rectParent.top + rectParent.bottom)/2, L"centers (y) should be equal");
	}

	TESTMETHOD(CloseCmdEndsDialog)
	{
		HWND dlg = dt->StartDialog(DialogThread::FindDialog());
		::SendMessage(dlg, WM_COMMAND, IDCANCEL, 0); 

		TddAssert().IsFalse(::IsWindowVisible(dlg), L"should have called ::EndDialog() by now");
	}
};
}